package com.tyk.bookstore.front.comment.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tyk.bookstore.front.comment.model.entity.CommentDo;
import com.tyk.bookstore.front.comment.model.entity.ReplyDo;
import com.tyk.bookstore.front.comment.model.query.CommentMinePageQuery;
import com.tyk.bookstore.front.comment.model.query.CommentOrderAddQuery;
import com.tyk.bookstore.front.comment.model.query.CommentPageQuery;
import com.tyk.bookstore.front.comment.model.result.CommentResultEnum;
import com.tyk.bookstore.front.comment.model.vo.CommentPageVo;
import com.tyk.bookstore.front.comment.model.vo.CommentVo;
import com.tyk.bookstore.front.comment.repository.CommentRepository;
import com.tyk.bookstore.front.comment.repository.ReplyRepository;
import com.tyk.bookstore.front.comment.service.CommentService;
import com.tyk.bookstore.front.comment.util.MapStructComment;
import com.tyk.bookstore.front.common.core.util.AssertUtil;
import com.tyk.bookstore.front.common.core.util.IdGenerator;
import com.tyk.bookstore.front.common.core.util.ObjUtil;
import com.tyk.bookstore.front.common.security.util.SecurityUtil;
import com.tyk.bookstore.front.member.model.dto.Member4CommentDto;
import com.tyk.bookstore.front.member.service.MemberApiService;
import com.tyk.bookstore.front.order.model.dto.Order4CommentDto;
import com.tyk.bookstore.front.order.service.OrderDetailApiService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author tyk
 * @description 评论管理
 */
@Service
@RequiredArgsConstructor
public class CommentServiceImp implements CommentService {
    private final CommentRepository commentRepository;
    private final ReplyRepository replyRepository;
    private final OrderDetailApiService orderDetailApiService;
    private final MemberApiService memberApiService;
    private final TransactionTemplate transactionTemplate;
    private final MapStructComment mapStructComment;

    @Override
    public CommentVo getById(Long id) {

        long memberId = StpUtil.getLoginIdAsLong();

        // 评论
        CommentDo cd = commentRepository.selectById(id);
        AssertUtil.notNull(cd, CommentResultEnum.COMMENT_NOT_FOUND);
        CommentVo cv = mapStructComment.toCommentVo(cd);

        // 回复
        LambdaQueryWrapper<ReplyDo> w = Wrappers.lambdaQuery(ReplyDo.class);
        w.eq(ReplyDo::getCommentId, id)
                .eq(ReplyDo::getMemberId, memberId);
        List<CommentVo.Reply> replyList = mapStructComment.toCommentVo$ReplyList(
                replyRepository.selectList(w)
        );


        // 会员名称
        HashSet<Long> midSet = new HashSet<>();
        midSet.add(cd.getMemberId());
        midSet.addAll(replyList.stream().map(CommentVo.Reply::getMemberId).toList());
        Map<Long, Member4CommentDto> mdMap = memberApiService
                .getMember4CommentDtoListByIdSet(midSet)
                .stream().collect(Collectors.toMap(Member4CommentDto::getMemberId, it -> it));


        // 评论-会员名称
        Member4CommentDto dto = mdMap.get(cv.getMemberId());
        cv.setMemberName(dto.getNickname())
                .setMemberAvatar(dto.getAvatar());
        // 回复-回复名称
        replyList.forEach(it -> {
                    Member4CommentDto md = mdMap.get(it.getMemberId());
                    it.setMemberName(md.getNickname())
                            .setMemberAvatar(md.getAvatar());
                }
        );

        // 设置回复列表
        cv.setChildren(replyList);

        return cv;
    }

    @Override
    public CommentPageVo getPage(CommentPageQuery query) {
        Page<CommentDo> page = new Page<>(query.getPage(), query.getLimit());
        LambdaQueryWrapper<CommentDo> w = Wrappers.lambdaQuery(CommentDo.class);
        w.eq(CommentDo::getBookId, query.getBookId());
        return getPage(page, w);
    }

    @Override
    public CommentPageVo getMinePage(CommentMinePageQuery query) {
        // 获取会员ID
        long memberId = SecurityUtil.getLoginId();
        // 设置查询条件
        Page<CommentDo> page = new Page<>(query.getPage(), query.getLimit());
        LambdaQueryWrapper<CommentDo> w = new LambdaQueryWrapper<>();
        w.eq(CommentDo::getMemberId, memberId);
        // 分页查询
        return getPage(page, w);
    }

    @Override
    public void add(CommentOrderAddQuery query) {
        long memberId = StpUtil.getLoginIdAsLong();

        transactionTemplate.executeWithoutResult(status -> {

            // 未评价
            AssertUtil.isFalse(
                    commentRepository.exist2Eq(
                            CommentDo::getOrderDetailId, query.getOrderDetailId(),
                            CommentDo::getMemberId, memberId,
                            CommentDo.class
                    ),
                    CommentResultEnum.COMMENT_ALREADY_EXIST
            );

            // 获取订单信息
            Order4CommentDto order = orderDetailApiService.getOrder4CommentDtoById(
                    query.getOrderDetailId(), memberId
            );

            // 订单已评价但被删除
            AssertUtil.isTrue(
                    ObjUtil.equal(order.getCommentId(), 0L),
                    CommentResultEnum.COMMENT_ALREADY_EXIST
            );

            // 评价
            CommentDo comment = mapStructComment.toCommentDo(query, order).setMemberId(memberId).setId(IdGenerator.id());
            commentRepository.insert(comment);

            // 更新订单详情中的评价ID
            orderDetailApiService.updateCommentId(comment.getId(), query.getOrderDetailId(), memberId);
        });
    }

    @Override
    public void deleteById(Long id) {

        long memberId = StpUtil.getLoginIdAsLong();

        // 评论存在
        AssertUtil.isTrue(
                commentRepository.exist2Eq(
                        CommentDo::getId, id,
                        CommentDo::getMemberId, memberId,
                        CommentDo.class
                ),
                CommentResultEnum.COMMENT_NOT_FOUND
        );

        // 删除评论及其回复
        transactionTemplate.executeWithoutResult(status -> {
            commentRepository.deleteById(id);
            replyRepository.delete1Eq(
                    ReplyDo::getCommentId, id,
                    ReplyDo.class
            );
        });

    }


    /**
     * 分页查询评论
     */
    private CommentPageVo getPage(Page<CommentDo> page, LambdaQueryWrapper<CommentDo> w) {

        w.orderBy(true, false, CommentDo::getCreateTime);

        // 评论
        commentRepository.selectPage(page, w);
        CommentPageVo pv = mapStructComment.toCommentPageVo(page);

        // 会员名称
        Map<Long, Member4CommentDto> mMap = memberApiService
                .getMember4CommentDtoListByIdSet(
                        pv.getRecords().stream().map(CommentPageVo.Comment::getMemberId).collect(Collectors.toSet())
                )
                .stream().collect(Collectors.toMap(
                        Member4CommentDto::getMemberId,
                        it -> it
                ));

        // 是否含有回复
        pv.getRecords().forEach(it -> {
            it.setHasReply(
                    replyRepository.exist1Eq(ReplyDo::getCommentId, it.getId(), ReplyDo.class)
            );
        });

        // 补充会员信息
        pv.getRecords().forEach(it -> {
            Member4CommentDto dto = mMap.get(it.getMemberId());
            it.setMemberName(dto.getNickname())
                    .setMemberAvatar(dto.getAvatar());
        });

        return pv;
    }

}
